Seeking With HTML+TIME

In HTML+TIME (Timed Interactive Multimedia Extensions) various types of media, animation, and other time elements can be played over a period of time. It is often desirable to be able to jump to any point on this time line. This process of jumping to different points on a time element's time line is called seeking. Click the following button to see examples of seeking within a video clip and an animation.

Code example: http://samples.msdn.microsoft.com/workshop/samples/author/behaviors/htmltime/seeking/seeking_intro.htm

This article introduces what types of media can have seeking applied and different ways to apply seeking.

The following topics are discussed in this document.

  • Prerequisites 
  • Seekable Media 
    • Audio and Video Time Elements 
    • Other Time Elements 
  • Tools for Seeking 
  • Related Topics

Prerequisites

It is assumed you know how to use Introduction to DHTML Behaviors, specifically, the time2 behavior of HTML+TIME. This article does not go into detail on how to add a behavior to your page, nor does it cover how to declare a namespace and use custom tags as required by the time2 behavior. These topics are covered in the HTML+TIME Overview and Spice Up Your Web Pages with HTML+TIME. You should have a basic working knowledge of Dynamic HTML (DHTML).

Seekable Media

Not all media types support seeking. In cases where seeking is not supported by the player, calls to seek methods are ignored. Seekable media can be broken up into two broad categories.

  • Time elements that play audio or video files
  • All other time elements

Audio and Video Time Elements

Time elements that play audio or video files are only seekable if the audio or video files they play are seekable. The following list shows the video and audio files that are NOT seekable.

  • Advanced Streaming Format (ASF) files
  • .wm files
  • .wmv files
  • Microsoft Windows Media Author files
  • Microsoft DirectMusic files
  • Any media referenced using an Advanced Stream Redirector (ASX) file

You can use the canSeek property to determine if media is seekable. For example, a time element like the following one, should not have any seeking methods applied to it.


Is the media seekable?
<!-- The inner text of this SPAN displays if the media is seekable or not. 
This is determined by the "canSeek" property that is retrieved when the 
media completes loading. In this case, "false" will be displayed. -->
<SPAN ID="oIsSeekableDisplay"></SPAN>
<!-- Because this t:MEDIA time element plays a wmv file, unpredictable
behavior will result from seeking on it.  -->
<t:MEDIA begin="indefinite" ID="oBeePlayer"
SRC="/workshop/samples/author/behaviors/media/bee.wmv"
onmediacomplete = "oIsSeekableDisplay.innerText = this.canSeek;"
/>

The best way to indicate whether the media file is capable of locating a specific time in the media's duration is to use the canSeek property.

Other Time Elements

All time elements that do not play audio or video files are seekable. Such time elements could be used for a variety of purposes such as animation and slide show presentations. You can seek on individual time elements directly or on time elements that have child time elements such as time containers. The following example shows how to seek on the time line of a t:ANIMATE element that animates the motion of a DIV element. By doing this, you can seek to different points in the progress of the animation.

Note  This example uses the slider behavior to provide the slide bar.


<!-- The slider control namespace is declared here. -->
<HTML XMLNS:t ="urn:schemas-microsoft-com:time" xmlns:control>
<HEAD>
<STYLE>
  .time    {behavior: url(#default#time2);}
  <!-- The slider htc is imported here. -->
  @media all
  {
      control\:slider {behavior:url(slider.htc);}
  }
</STYLE>
<?IMPORT namespace="t" implementation="#default#time2">

<SCRIPT LANGUAGE="JScript">

// This function is fired whenever the seekActiveTime slide bar changes value.
function fnChangeActiveBar()
{
    // If the media is not active then make it active. This makes it 
    // possible to start the media back up again by just dragging the 
    // slide bar to some value.
    if(!oAnim.currTimeState.isActive)
    {
        oAnim.beginElement()
    }
    // The "seekActiveTime" method specifies the time in seconds to seek to
    // on the time line of the t:ANIMATE element.
    oAnim.seekActiveTime(oActiveTimeSlider.value);
}
</SCRIPT>
</HEAD>

<BODY>
<IMG ID="oDiv" SRC="/workshop/graphics/ART_time_progress.gif" 
STYLE="position:absolute; left:50px; top:200px;z-index:0;">

<!-- This DIV is the red bar that moves across the table showing the progress
of the animation. -->
<DIV CLASS="time" 
STYLE="width:4px;height:55px;background-color:red;position:absolute;top:200px;left:50px;z-index:2;">
<t:ANIMATE ID="oAnim" BEGIN="indefinite" dur="8" FILL="hold" ATTRIBUTENAME="left" 
FROM="50px" TO="450px"/>
</DIV>
<!-- This is the slider. -->
<control:slider style="width:450px;sl--tick-style:none;" MIN="0" ID="oActiveTimeSlider" 
TICKINTERVAL=".1" TICKNUMBER="80" onchange="fnChangeActiveBar();">
</control:slider>

</BODY>
</HTML>

Code example: http://samples.msdn.microsoft.com/workshop/samples/author/behaviors/htmltime/seeking/seekTimeElement.htm

Time container elements such as t:SEQ, t:EXCL, and t:PAR define an encapsulated time line for any number of child time elements of the container. When you seek on a time container, you are jumping to any point on that time line. In the following example, a t:seq container element contains several time elements that act as an animated slide show. By seeking on the t:SEQ element, the user is able to jump to any point on the time line of this slide show.


<HTML xmlns:t= "urn:schemas-microsoft-com:time" xmlns:control>
<HEAD>
<?IMPORT namespace="t" implementation="#default#time2">
<STYLE>
    @media all
    {
        control\:slider {behavior:url(slider.htc);}
    }
    .time{behavior:url(#default#time2)}
    .label1{font-size:10pt;color:#99CCFF;position:absolute; top:110px;left:10px;}
    .label2{font-size:10pt;color:white;position:absolute; top:160px;left:10px;}
    .label3{font-size:16pt;width:20px;color:red;position:absolute;writing-mode:tb-rl;top:60px;left:10px;}
    .label4{font-size:24pt;color:black;position:absolute; top:90px;left:10px;}
</STYLE>
<SCRIPT>
// This function is fired whenever the slide bar changes value.
function fnChangeBar()
{
    // If the media is not active then make it active. This makes it 
    // possible to start the media back up again by just dragging the 
    // slide bar to some value.
    if(!oSeq.currTimeState.isActive)
    {
        oSeq.beginElement()
    }
    // If the slider value is being moved by the user, the media will seek
    // to the user specified value.
    if(Math.round(oSlider.value)!=Math.round(oSeq.currTimeState.segmentTime))
    {
        oSeq.seekSegmentTime(oSlider.value)
    }
}
</SCRIPT>
</HEAD>

<BODY>        
<B>Media timer:</B>
<!-- The SPAN element below serves two purposes. First, it displays where on 
its time line the media is. Second, it changes the value of the slide bar every
second to show the progression of the animation on the slide bar. -->
<SPAN ID="Timer" CLASS="time" BEGIN="oSeq.begin" END="oSeq.end" DUR="1" 
REPEATCOUNT="indefinite" FILL="hold" 
onrepeat="this.innerText=oSeq.currTimeState.segmentTime;oSlider.value=oSeq.currTimeState.segmentTime;">0</SPAN>
 
<BR><BR>
<DIV STYLE="height:300px;">
<t:SEQ ID="oSeq" REPEATCOUNT="indefinite" DUR="18" BEGIN="indefinite">
    <t:PAR TIMEACTION="display" DUR="4">
        <SPAN ID="oSpan" CLASS="time label1">
            ...so I left my Home,
            <t:ANIMATE DUR="3" ATTRIBUTENAME="fontSize" FROM="10px" FILL="hold" TO="20pt"/>
        </SPAN>
        <t:IMG ID="one" SRC="/workshop/samples/author/behaviors/media/home.gif"/>
    </t:PAR>
    <t:PAR TIMEACTION="display" DUR="4">
        <SPAN ID="oSpan" CLASS="time label2">
            took the road less travelled,
            <t:ANIMATE DUR="3" ATTRIBUTENAME="fontSize" FROM="10px" FILL="hold" TO="20pt"/>
        </SPAN>
        <t:IMG ID="two" SRC="/workshop/samples/author/behaviors/media/country_road.gif"/>
    </t:PAR>
    <t:PAR TIMEACTION="display" DUR="4">
        <SPAN ID="oSpan" CLASS="time label3">
            to the end of the world,
            <t:ANIMATE DUR="3" ATTRIBUTENAME="left" FROM="10px" FILL="hold" TO="380px"/>
        </SPAN>
        <t:IMG ID="four" SRC="/workshop/samples/author/behaviors/media/shore.gif"/>
    </t:PAR>
    <t:PAR TIMEACTION="display" DUR="6" >
        <SPAN ID="oSpan" CLASS="time label4">
            and past the edge of my memory.
            <t:ANIMATECOLOR BEGIN="1" DUR="3" ATTRIBUTENAME="color" FROM="black" FILL="hold" TO="white"/>
        </SPAN>
        <t:IMG ID="three" SRC="/workshop/samples/author/behaviors/media/greece.gif"/>
    </t:PAR>
</t:SEQ>
</DIV>

<control:slider style="width:200px" ID="oSlider" VALUE="0" MIN="0" TICKINTERVAL="1" 
TICKNUMBER="18" onchange="fnChangeBar();">
</control:slider>

</BODY>
</HTML>

Code example: http://samples.msdn.microsoft.com/workshop/samples/author/behaviors/htmltime/seeking/seqSeek.htm

Tools for Seeking

There are a number of HTML+TIME components that can be used in markup or in script to facilitate seeking on time elements. The following table lists some of these components.

Component Name Description
seekSegmentTime A method that locates the specified point on the element's segment time line and begins playing from that point. The segment consists of one repetition of the time line including reverse play using the AUTOREVERSE attribute.
seekTo A method similar to the seekSegmentTime method except that if there are multiple repetitions of the active time, you can specify which repetition of the time line to use.
seekActiveTime A method that locates a specified point on the element's active time line and begins playing from that point. This active time line includes all segment repetitions.
seekToFrame A method that locates a specified frame in the object. This only applies to media types that have frames such as video files.
onseek An event that fires whenever a seek operation is performed on the element.
canSeek A property that retrieves a value that indicates whether the media file is capable of locating a specific time in the media's duration.

The seekSegmentTime, seekTo, and seekActiveTime methods all use seconds as the parameter to determine when in a time element's time line to seek to. The differences among the methods lie in how they handle repetitions of the time line. The following example shows a simple animation that repeats five times with an AUTOREVERSE attribute value of true. Three slider bars are provided to allow you to use the seekSegmentTime, seekTo, or seekActiveTime method to seek on the animation of a time element.

Code example: http://samples.msdn.microsoft.com/workshop/samples/author/behaviors/htmltime/seeking/seekMethods.htm

Rather than using time in seconds as the parameter to determine where in the time line to seek to, the seekToFrame method uses the number of frames to determine where to jump to. While the first group of methods can be used on all seekable media, the seekToFrame method can only be used on media types that have frames such as video files. The following shows an example of using the seekToFrame method to seek within the time line of video playback.


<HTML xmlns:t= "urn:schemas-microsoft-com:time">
<HEAD>
<?IMPORT namespace="t" implementation="#default#time2">
<STYLE>
    .time{behavior:url(#default#time2)}
</STYLE>
<SCRIPT>
function doSeekToFrame(){
    //If you attempt to seek to a time on an object that is not currently 
    //active, an error is generated. To prevent this, check the object's 
    //status using the isActive property.
    //Is media object active?
    //Yes, continue and do seek.
    //No, restart element using the beginElement method.
    if(!oMedia.currTimeState.isActive){
        oMedia.beginElement();
    }
    //Is user input valid and within the media's duration boundaries?
    //Video has a total of 597 frames.
    if(isFinite(seekFrame.value) && seekFrame.value >= 1 && seekFrame.value < 598){
    oMedia.seekToFrame(seekFrame.value);
    }
    else
    {
        //Input is not valid, alert user to re-enter choice.
        alert("Please enter a valid integer. Possible values are 1 to 597 inclusive.");
        seekFrame.value = "";
        seekFrame.focus();
    }
}
</SCRIPT>
</HEAD>
<BODY>        
<B>Media timer:</B>
<SPAN id="Timer2" class="time" dur=".01" repeatCount="indefinite" fill="hold" onrepeat="innerText=parseInt(oMedia.currTimeState.activeTime);">0</SPAN>

<t:video style="width:175px; height:150px;" id="oMedia" src="movie.avi"/>

Current frame: 
<SPAN id="oCurrFrame" class="time" dur="0.01" repeatCount="indefinite" 
fill="hold" onrepeat="innerText=parseInt(oMedia.currentFrame);"></SPAN> 
<BR><BR>
<B>Frame to seek to</B>: 
<INPUT type="text" value="" name="seekFrame" size="3"/>&nbsp;seconds
<BR><BR>
<BUTTON id="seekBtn" onClick="doSeekToFrame();">Click to seek</BUTTON>&nbsp;
<BUTTON onClick="oMedia.beginElement()">Restart</BUTTON>

</BODY>
</HTML>

Code example: http://samples.msdn.microsoft.com/workshop/samples/author/behaviors/seekToFrame.htm

Note  If you attempt to seek to a time on an object that is not currently active, an error is generated. To prevent this, check the object's status using the isActive property, which is demonstrated in the preceding example.